﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.SqlClient;
using System.Linq;
using System.Linq.Expressions;
using System.Data.Entity.Validation;
using XiaoYuStock.Model;
using XiaoYuStock.Model.Models; 
using System.Text;
using XiaoYuStock.Core;
namespace XiaoYuStockAnalysis.BusinessLogic
{
    /// <summary>
    /// EntityFramework仓储操作基类
    /// </summary>
    /// <typeparam name="T">动态实体类型</typeparam>
    /// <typeparam name="TKey">实体主键类型</typeparam>
    public class DBRepositoryBase<T> where T : class
    {
        protected DbContext DB = new ShareContext();

        /// <summary>
        /// 提交并保存到数据库
        /// </summary>
        /// <returns></returns>
        public int CommitSaveChanges()
        {
            try
            {
                return DB.SaveChanges();
            }
            catch (DbEntityValidationException ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 获取当前单元操作是否已被提交
        /// </summary>
        public bool IsCommitted { get; private set; }

        /// <summary>
        /// 提交当前单元操作的结果
        /// </summary>
        /// <returns></returns>
        public int Commit()
        {
            if (IsCommitted)
            {
                return 0;
            }
            try
            {
                int res = CommitSaveChanges();
                IsCommitted = true;
                return res;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public T Add(T entity)
        {
            try
            {
                DB.Entry<T>(entity).State = System.Data.Entity.EntityState.Added;
                DB.SaveChanges();
                return entity;
            }
            catch (DbEntityValidationException ex)
            {
                StringBuilder errors = new StringBuilder();
                IEnumerable<DbEntityValidationResult> validationResult = ex.EntityValidationErrors;
                foreach (DbEntityValidationResult result in validationResult)
                {
                    ICollection<DbValidationError> validationError = result.ValidationErrors;
                    foreach (DbValidationError err in validationError)
                    {
                        errors.Append(err.PropertyName + ":" + err.ErrorMessage + "\r\n");
                    }
                }
                LogHelper.Error("BaseRepository-Add ex:" + errors.ToString());
                return null;
            }
            catch (Exception e)
            {
                LogHelper.Error("BaseRepository-Add :" + e.Message);
                return null;
            }
        }

        /// <summary>
        /// 增加
        /// </summary>
        /// <param name="model">实体</param>
        /// <param name="autoCommit">是否自动提交，默认自动提交</param>
        /// <returns></returns>
        public T Insert(T model, bool autoCommit = true)
        {
            //DB.Configuration.AutoDetectChangesEnabled = false;
            EntityState state = DB.Entry(model).State;
            if (state == EntityState.Detached)
            {
                DB.Set<T>().Add(model);
                DB.Entry(model).State = EntityState.Added;
            }
            if (autoCommit)
            {
                CommitSaveChanges();
            }
            //DB.Configuration.AutoDetectChangesEnabled = true;
            return model;
        }

        /// <summary>
        /// 插入实体记录
        /// </summary>
        /// <param name="model"></param>
        /// <param name="autoCommit"></param>
        /// <returns></returns>
        public int _Insert(T model, bool autoCommit = true)
        {
            EntityState state = DB.Entry(model).State;
            if (state == EntityState.Detached)
            {
                DB.Set<T>().Add(model);
                DB.Entry(model).State = EntityState.Added;
            }
            IsCommitted = false;
            return autoCommit ? Commit() : 0;
        }

        /// <summary>
        /// 批量插入实体记录集合
        /// </summary>
        /// <param name="entities"> 实体记录集合 </param>
        /// <param name="autoCommit"> 是否自动提交 </param>
        /// <returns> 操作影响的行数 </returns>
        public int _Insert(IEnumerable<T> entities, bool autoCommit = true)
        {
            try
            {
                DB.Configuration.AutoDetectChangesEnabled = false;
                foreach (T entity in entities)
                {
                    EntityState state = DB.Entry(entity).State;
                    if (state == EntityState.Detached)
                    {
                        DB.Set<T>().Add(entity);
                        DB.Entry(entity).State = EntityState.Added;
                    }
                    IsCommitted = false;
                }
            }
            finally
            {
                DB.Configuration.AutoDetectChangesEnabled = true;
            }
            return autoCommit ? Commit() : 0;
        }

        /// <summary>
        /// 删除指定Id的记录
        /// </summary>
        /// <param name="id">id</param>
        /// <param name="autoCommit">是否自动提交，默认自动提交</param>
        /// <returns></returns>
        public bool Delete(int id, bool autoCommit = true)
        {
            T entity = DB.Set<T>().Find(id);
            return entity != null ? Delete(entity, autoCommit) : false;
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="autoCommit">是否自动提交，默认自动提交</param>
        /// <returns></returns>
        public bool Delete(T entity, bool autoCommit = true)
        {
            DB.Entry(entity).State = EntityState.Deleted;
            bool success = false;
            if (autoCommit)
            {
                success = CommitSaveChanges() > 0;
            }
            return success;
        }

        ///// <summary>
        ///// 删除实体记录集合
        ///// </summary>
        ///// <param name="entities"> 实体记录集合 </param>
        ///// <param name="isSave"> 是否执行保存 </param>
        ///// <returns> 操作影响的行数 </returns>
        //public virtual int Delete(IEnumerable<T> entities, bool isSave = true)
        //{
        //    try
        //    {
        //        DB.Configuration.AutoDetectChangesEnabled = false;
        //        foreach (T entity in entities)
        //        {
        //            DB.Entry(entity).State = EntityState.Deleted;
        //            IsCommitted = false;
        //        }
        //    }
        //    finally
        //    {
        //        DB.Configuration.AutoDetectChangesEnabled = true;
        //    }
        //    return isSave ? Commit() : 0;
        //}

        ///// <summary>
        ///// 删除所有符合特定表达式的数据
        ///// </summary>
        ///// <param name="predicate"> 查询条件谓语表达式 </param>
        ///// <param name="isSave"> 是否执行保存 </param>
        ///// <returns> 操作影响的行数 </returns>
        //public virtual int Delete(Expression<Func<T, bool>> predicate, bool isSave = true)
        //{
        //    CommonHelper.CheckArgument(predicate, "predicate");
        //    List<T> entities = DB.Set<T>().Where(predicate).ToList();
        //    return entities.Count > 0 ? Delete(entities, isSave) : 0;
        //}


        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="autoCommit">是否自动提交，默认自动提交</param>
        /// <returns></returns>
        public bool Update(T entity, bool autoCommit = true)
        {
            DbEntityEntry<T> entry = DB.Entry(entity);
            if (entry.State == EntityState.Detached)
            {
                DB.Set<T>().Attach(entity);
                entry.State = EntityState.Modified;
            }
            bool success = false;
            if (autoCommit)
            {
                success = CommitSaveChanges() > 0;
            }
            return success;
        }

        /// <summary>
        /// 更新实体集合
        /// </summary>
        /// <param name="listEntity">实体集合</param>
        /// <param name="autoCommit">是否自动提交，默认自动提交</param>
        /// <returns></returns>
        public bool Update(List<T> listEntity, bool autoCommit = true)
        {
            //DB.Configuration.AutoDetectChangesEnabled = false;
            foreach (T entity in listEntity)
            {
                DbEntityEntry<T> entry = DB.Entry(entity);
                if (entry.State == EntityState.Detached)
                {
                    DB.Set<T>().Attach(entity);
                    entry.State = EntityState.Modified;
                }
            }
            bool success = false;
            if (autoCommit)
            {
                success = CommitSaveChanges() > 0;
            }
            return success;
            //DB.Configuration.AutoDetectChangesEnabled = true;
        }

        ///// <summary>
        ///// 使用附带新值的实体信息更新指定实体属性的值
        ///// </summary>
        ///// <param name="propertyExpression">属性表达式</param>
        ///// <param name="isSave">是否执行保存</param>
        ///// <param name="entity">附带新值的实体信息，必须包含主键</param>
        ///// <returns>操作影响的行数</returns>
        //public int Update(Expression<Func<T, object>> propertyExpression, T entity, bool isSave = true)
        //{
        //    //  throw new NotSupportedException("上下文公用，不支持按需更新功能。");

        //    CommonHelper.CheckArgument(propertyExpression, "propertyExpression");
        //    CommonHelper.CheckArgument(entity, "entity");

        //    DB.Update<TEntity, TKey>(propertyExpression, entity);
        //    IsCommitted = false;

        //    if (isSave)
        //    {
        //        var dbSet = DB.Set<T>();
        //        dbSet.Local.Clear();
        //        var entry = DB.Entry(entity);
        //        return Commit(false);
        //    }
        //    return 0;
        //}

        /// <summary>
        /// 查找指定Id的实体记录
        /// </summary>
        /// <param name="id">id</param>
        /// <returns></returns>
        public T GetById(int id)
        {
            return DB.Set<T>().Find(id);
        }

        /// <summary>
        /// 统计
        /// </summary>
        /// <param name="id">id</param>
        /// <returns></returns>
        public int Count(Expression<Func<T, bool>> where)
        {
            return DB.Set<T>().Where(where).Count();
        }


        /// <summary>
        /// 查询指定条件记录是否存在
        /// </summary>
        /// <param name="where">查找条件</param>
        /// <returns>bool</returns>
        public bool Any(Expression<Func<T, bool>> where)
        {
            return DB.Set<T>().Any(where);
        }

        public bool Exist(Expression<Func<T, bool>> anyLambda)
        {
            return DB.Set<T>().Any(anyLambda);
        }


        /// <summary>
        /// 根据条件表达式查询返回一条记录
        /// </summary>
        /// <param name="where">查找条件</param>
        /// <returns>一条记录</returns>
        public T Find(Expression<Func<T, bool>> where)
        {
            return DB.Set<T>().FirstOrDefault(where);
        }

    
        public IQueryable<T> FindList<S>(Expression<Func<T, bool>> whereLamdba, string orderName, bool isAsc)
        {
            var _list = DB.Set<T>().AsNoTracking().Where<T>(whereLamdba);
            _list = OrderBy(_list, orderName, isAsc);
            return _list;
        }

        public IQueryable<T> QueryPageList<S>(int pageIndex, int pageSize, out int totalRecord, Expression<Func<T, bool>> whereLamdba, bool isAsc, Expression<Func<T, S>> orderLamdba)
        {
            var _list = DB.Set<T>().Where<T>(whereLamdba);
            totalRecord = _list.Count();
            if (isAsc)
            {
                _list = _list.OrderBy(orderLamdba).Skip<T>((pageIndex - 1) * pageSize).Take<T>(pageSize);
            }
            else
            {
                _list = _list.OrderByDescending(orderLamdba).Skip<T>((pageIndex - 1) * pageSize).Take<T>(pageSize);
            }
            return _list;
        }


        private IQueryable<T> OrderBy(IQueryable<T> source, string propertyName, bool isAsc)
        {
            if (source == null) throw new ArgumentNullException("source", "source is null");
            if (string.IsNullOrEmpty(propertyName)) return source;
            var _parameter = Expression.Parameter(source.ElementType);
            var _property = Expression.Property(_parameter, propertyName);
            if (_property == null) throw new ArgumentNullException("propertyName", "propertyName is null");
            var _lambda = Expression.Lambda(_property, _parameter);
            var _methodName = isAsc ? "OrderBy" : "OrderByDescending";
            var _resultExpression = Expression.Call(typeof(Queryable), _methodName, new Type[] { source.ElementType, _property.Type }, source.Expression, Expression.Quote(_lambda));
            return source.Provider.CreateQuery<T>(_resultExpression);

        }


        public bool Truncate(Expression<Func<T, bool>> whereLamdba)
        {
            var lists = DB.Set<T>().Where<T>(whereLamdba);
            DB.Set<T>().RemoveRange(lists);
            return DB.SaveChanges() > 0;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TT"></typeparam>
        /// <param name="sql"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public virtual IQueryable<TT> ExtensionEntitys<TT>(string sql, object[] param) where TT : class
        {
            //CommonHelper.CheckArgument(sql, "sql");
            if (param != null)
            {
                //CommonHelper.CheckArgument(param, "param");
                return DB.Database.SqlQuery<TT>(sql, param).AsQueryable();
            }
            else
            {
                return DB.Database.SqlQuery<TT>(sql).AsQueryable();
            }
        }
    }
}
